package ws.performancetest.tests.jdbcdriver;

import java.sql.SQLException;
import java.sql.Statement;
import ws.performancetest.api.AbstractTestSuite;
import ws.performancetest.api.exception.TestExecutionException;
import ws.performancetest.api.exception.TestSuiteSetupException;
import ws.utils.jdbc.DBManager;
import ws.utils.thread.ThreadManager;

/**
 *
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public abstract class AbstractDriverTest extends AbstractTestSuite {

  protected final DBManager dbmanager;
  protected final String testTable = "Std_Student";
  protected final String sqlQuery = "SELECT * FROM " + testTable;
  private final String sqlCreateTestTable = "CREATE TABLE " + testTable + "(\n"
          + "  Std_id          INT PRIMARY KEY IDENTITY,\n"
          + "  Std_firstName   NVARCHAR(25) NOT NULL,\n"
          + "  Std_lastName    NVARCHAR(50) NOT NULL,\n"
          + "  Std_RegDate     DATETIME,\n"
          + "  Std_applGrade   FLOAT,\n"
          + "  StdCrs_id       INT,\n"
          + "  Std_birthDate   DATETIME,\n"
          + "  Std_eMail       NVARCHAR(25)\n"
          + ")\n";

  public AbstractDriverTest(String resultTable, String summaryTable) throws TestSuiteSetupException, SQLException {
    super(resultTable, summaryTable);

    dbmanager = new DBManager();

    if (!dbmanager.existsTable(testTable)) {
      dbmanager.executeUpdate(sqlCreateTestTable);
      if (DEBUG) {
        System.out.println(testTable + " table created.");
      }
    }
  }

  protected void createTestData() throws SQLException {
    createTestData(numberOfThreads * cycleCount);
  }

  protected void createTestData(int rowCount) throws SQLException {
    Statement stmt = con.createStatement();
    for (int i = 0; i < rowCount; ++i) {
      String batch = "INSERT INTO " + testTable
              + " VALUES("
              + "'StdF " + i + "'"
              + ", 'StdL " + i + "'"
              + ", " + i
              + ", " + 16.0
              + ", " + i
              + ", " + i
              + ", 'std" + i + "@mail.com'"
              + ")";
      stmt.addBatch(batch);
    }
    stmt.executeBatch();
  }

  protected void deleteTestData() throws SQLException {
    dbmanager.clearTableContents(testTable);
  }

  protected void executeReadOrUpdateTest(Class<? extends Runnable> task, ISetup testSetup) throws TestExecutionException {
    try {
      deleteTestData();
      createTestData();

      executeTest(task, testSetup);
    } catch (Exception ex) {
      throw new TestExecutionException(ex);
    }
  }

  protected void executeInsertTest(Class<? extends Runnable> task, ISetup testSetup) throws TestExecutionException {
    try {
      deleteTestData();

      executeTest(task, testSetup);
    } catch (Exception ex) {
      throw new TestExecutionException(ex);
    }
  }

  protected void executeDeleteTest(Class<? extends Runnable> task, ISetup testSetup) throws TestExecutionException {
    try {
      deleteTestData();
      createTestData();

      executeTest(task, testSetup);
    } catch (Exception ex) {
      throw new TestExecutionException(ex);
    }
  }

  private void executeTest(Class<? extends Runnable> task, ISetup testSetup) throws SQLException, InstantiationException, IllegalAccessException, InterruptedException {
    long t_start, t_finish;

    /* Measure setup time. */
    t_start = System.nanoTime();
    testSetup.setup();
    threadManager = new ThreadManager(numberOfThreads, task);
    t_finish = System.nanoTime();
    long setupTime = (long) ((t_finish - t_start) / 1e5); // convert to a 10th of a milissecond

    /* Measure execution time. */
    t_start = System.nanoTime();
    threadManager.startThreads();
    threadManager.waitForThreads();
    t_finish = System.nanoTime();
    addLog((long) ((t_finish - t_start) / 1e5), setupTime);
  }

  public interface ISetup {

    public void setup() throws SQLException;
  }
}
